{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# <center>第6章 面向对象编程进阶</center>\n",
    "\n",
    "<br>\n",
    "\n",
    "- [6.1 类的定制](#6.1-类的定制)\n",
    "  - [6.1.1 常用特殊属性](#6.1.1-常用特殊属性)\n",
    "  - [6.1.2 对象运算（运算符重载）](#6.1.2-对象运算（运算符重载）)\n",
    "  - [6.1.3 对象描述](#6.1.3-对象描述)\n",
    "  - [6.1.4对象成员访问控制](#6.1.4对象成员访问控制)\n",
    "  - [6.1.5 描述器](#6.1.5-描述器)\n",
    "  - [6.1.6 可调用对象](#6.1.6-可调用对象)\n",
    "  - [6.1.7 容器](#6.1.7-容器)\n",
    "  - [6.1.8 迭代器与可迭代对象](#6.1.8-迭代器与可迭代对象)\n",
    "- [6.2 生成器](#6.2-生成器)\n",
    "  - [6.2.1 生成器的创建](#6.2.1-生成器的创建)\n",
    "  - [6.2.2 生成器与迭代器](#6.2.2-生成器与迭代器)\n",
    "- [6.3 类装饰器](#6.3-类装饰器)\n",
    "  - [6.3.1 修饰方法的装饰器](#6.3.1-修饰方法的装饰器)\n",
    "  - [6.3.2 修饰类的装饰器](#6.3.2-修饰类的装饰器)\n",
    "  - [6.3.3 基于类的装饰器*](#6.3.3-基于类的装饰器*)\n",
    "- [6.4 抽象基类*](#6.4-抽象基类*)\n",
    "  - [6.4.1 抽象基类的概念](#6.4.1-抽象基类的概念)\n",
    "  - [6.4.2 抽象基类的应用](#6.4.2-抽象基类的应用)\n",
    "  - [6.4.3 自定义抽象基类](#6.4.3-自定义抽象基类)\n",
    "- [6.5 元类*](#6.5-元类*)\n",
    "  - [6.5.1 Python类的特征](#6.5.1-Python类的特征)\n",
    "  - [6.5.2 元类的定义与使用](#6.5.2-元类的定义与使用)\n",
    "  - [6.5.3 元类的应用实例](#6.5.3-元类的应用实例)\n",
    "- [6.6 对象序列化*](#6.6-对象序列化*)\n",
    "  - [6.6.1 pickle](#6.6.1-pickle)\n",
    "  - [6.6.2 copyreg](#6.6.2-copyreg)\n",
    "  - [6.6.3 shelve](#6.6.3-shelve)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 6.1 类的定制\n",
    "\n",
    "- 特殊属性和特殊方法\n",
    "  - 又称为魔法属性或魔法方法\n",
    "- 协议\n",
    "  - 一组非强制性的特殊方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 6.1.1 常用特殊属性\n",
    "\n",
    "#### `__dict__`\n",
    "\n",
    "- `__dict__`是一个属性字典\n",
    "- 多数数据类型都有自己的`__dict__`属性\n",
    "  - 模块：模块中定义的函数、类、变量等构成的字典\n",
    "  - 函数：初始状态为空字典\n",
    "  - 类：普通方法、类方法、静态方法、类属性\n",
    "  - 对象：实例属性\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "def test_dict():\n",
    "    pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{}"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "test_dict.__dict__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'x': 0}"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "test_dict.x = 0\n",
    "test_dict.__dict__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "class TestDict:\n",
    "    x_class = 0\n",
    "    def __init__(self):\n",
    "        self.x_obj = 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "mappingproxy({'__module__': '__main__',\n",
       "              'x_class': 0,\n",
       "              '__init__': <function __main__.TestDict.__init__(self)>,\n",
       "              '__dict__': <attribute '__dict__' of 'TestDict' objects>,\n",
       "              '__weakref__': <attribute '__weakref__' of 'TestDict' objects>,\n",
       "              '__doc__': None})"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "TestDict.__dict__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'x_obj': 1}"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "td = TestDict()\n",
    "td.__dict__"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 派生类的`__dict__`不会继承基类的`__dict__`属性，它们的`__dict___`是独立的"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "class SubTestDict(TestDict):\n",
    "    y_class = 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "mappingproxy({'__module__': '__main__', 'y_class': 2, '__doc__': None})"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "SubTestDict.__dict__"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 一些内置数据类型的实例没有`__dict__`属性\n",
    "  - `list`、`dict`、`set`、`tuple`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "'list' object has no attribute '__dict__'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-10-95dfd23436f0>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0ml\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0ml\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__dict__\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m: 'list' object has no attribute '__dict__'"
     ]
    }
   ],
   "source": [
    "l = []\n",
    "l.__dict__"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "####  `__base__`与`__bases__`\n",
    "\n",
    "- `__base__`\n",
    "  - 当前类的基类\n",
    "  - 多重继承的情况下是第一个基类\n",
    "- `__bases__`\n",
    "  - 当前类的所有基类构成的元组"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### `__slots__`\n",
    "\n",
    "- 用于指定一组实例属性名称，实例属性的名字只能来自其中\n",
    "- 类中包含`__slots__`属性时\n",
    "  - 利用固定大小的数组来存储实例属性\n",
    "  - 实例不再有`__dict__`属性\n",
    "  - 能够节约内存空间"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "class TestSlot1:\n",
    "    def __init__(self):\n",
    "        self.x = 0\n",
    "        self.y = 1\n",
    "\n",
    "class TestSlot2:\n",
    "    __slots__ = ['x', 'y']\n",
    "    def __init__(self):\n",
    "        self.x = 0\n",
    "        self.y = 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'x': 0, 'y': 1}"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ts1 = TestSlot1()\n",
    "ts2 = TestSlot2()\n",
    "ts1.__dict__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "'TestSlot2' object has no attribute 'm'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-5-96e2e2204de7>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mts2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mm\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m: 'TestSlot2' object has no attribute 'm'"
     ]
    }
   ],
   "source": [
    "ts2.m=0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 不在`__slots__`中的属性不能被动态绑定\n",
    "  - 用于限制实例的动态绑定"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "def fun(self):\n",
    "    pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "ts1.fun = fun"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "'TestSlot2' object has no attribute 'fun'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-16-192314586c86>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mts2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfun\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfun\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m: 'TestSlot2' object has no attribute 'fun'"
     ]
    }
   ],
   "source": [
    "ts2.m = fun"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 6.1.2 对象运算（运算符重载）\n",
    "\n",
    "- Python中运算符的的执行过程实际上是调用了对象的特殊方法\n",
    "  - 例如，`+`运算符相当于`__add__`方法，`-`运算符相当于`__sub__`方法\n",
    "- 在类定义中根据需要实现这些方法，其实例之间就能够利用运算符进行运算"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "x, y = 1, 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x + y\n",
    "x.__add__(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-1"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x - y\n",
    "x.__sub__(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "class PointwiseVector:\n",
    "    def __init__(self, value):\n",
    "        self.v = value\n",
    "\n",
    "    def check_len(self, o):\n",
    "        if len(o.v) != len(self.v):\n",
    "            return False\n",
    "        return True\n",
    "\n",
    "    def __add__(self, o):\n",
    "        if not self.check_len(o):\n",
    "            return None\n",
    "        return self.__class__([v1 + v2 for v1, v2 in zip(self.v, o.v)])\n",
    "\n",
    "    def __sub__(self, o):\n",
    "        if not self.check_len(o):\n",
    "            return None\n",
    "        return self.__class__([v1 - v2 for v1, v2 in zip(self.v, o.v)])\n",
    "\n",
    "    def __mul__(self, o):\n",
    "        if not self.check_len(o):\n",
    "            return None\n",
    "        return self.__class__([v1 * v2 for v1, v2 in zip(self.v, o.v)])\n",
    "\n",
    "    def __truediv__(self, o):\n",
    "        if not self.check_len(o):\n",
    "            return None\n",
    "        return self.__class__([v1 / v2 for v1, v2 in zip(self.v, o.v)])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "o1 = PointwiseVector([1, 2, 3])\n",
    "o2 = PointwiseVector([1, 2, 3])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[2, 4, 6]"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(o1 + o2).v"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[0, 0, 0]"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(o1 - o2).v"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 4, 9]"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(o1 * o2).v"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1.0, 1.0, 1.0]"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(o1 / o2).v"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 常用运算符的特殊方法\n",
    "\n",
    "|运算符|特殊方法|作用|\n",
    "|:--|:--|:--|\n",
    "|`+`、`-`、`*`、`/`、`**`|`__add__`、`__sub__`、`__mul__`、`__truediv__`、`__pow__`|算术运算符|\n",
    "|`%`、`//`|`__mod__`、`__floordiv__`|取余、整除|\n",
    "|`+x`、`-x`|`__pos__`、`__neg__`|正、负|\n",
    "|`>`、`>=`、`<`、`<=`、`==`、`！=`|`__gt__`、`__ge__`、`__lt__`、`__le__`、`__eq__`、`__ne__`|比较运算符|\n",
    "|`+=`、`-=`、`*=`、`/=`|`__iadd__`、`__isub__`、`__imul__`、`__idiv__`|增强运算符|"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 反向的特殊方法\n",
    "  - 当两个对象利用双目运算符时，首先检查左侧的对象是否实现了相应的特殊方法，如果有则调用左侧对象中的方法；否则，检查右侧的对象是否定义反向的特殊方法\n",
    "  - 所有双目运算符都有对应的反向特殊方法\n",
    "    - `__add__`的反向特殊方法为`__radd__`\n",
    "    - `__sub__`的反向特殊方法为`__rsub__`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "code_folding": [],
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "class Left:\n",
    "    def __init__(self, v):\n",
    "        self.v = v\n",
    "\n",
    "class Right:\n",
    "    def __init__(self, v):\n",
    "        self.v = v\n",
    "\n",
    "    def __radd__(self, o):\n",
    "        return self.v + o.v\n",
    "\n",
    "    def __rsub__(self, o):\n",
    "        return o.v -  self.v"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "l = Left(2)\n",
    "r = Right(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "l + r"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "unsupported operand type(s) for +: 'Right' and 'Left'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-31-dee0167d7375>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mr\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0ml\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m: unsupported operand type(s) for +: 'Right' and 'Left'"
     ]
    }
   ],
   "source": [
    "r + l"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 6.1.3 对象描述\n",
    "\n",
    "- `print`函数打印至输出终端\n",
    "  - `__str__`\n",
    "  - `str(obj)`\n",
    "- 在交互式环境中显示对象\n",
    "  - `__repr__`\n",
    "  - `repr(obj)`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [],
   "source": [
    "pv = PointwiseVector([1, 2, 3])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<__main__.PointwiseVector object at 0x10ee99c10>\n"
     ]
    }
   ],
   "source": [
    "print(pv) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<__main__.PointwiseVector at 0x10ee99c10>"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pv"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "class PointwiseVector:\n",
    "    def __init__(self, value):\n",
    "        self.v = value\n",
    "\n",
    "    # 略去其他方法的定义\n",
    "        \n",
    "    def __str__(self):\n",
    "        print('__str__方法被调用')\n",
    "        return str(self.v)\n",
    "\n",
    "    def __repr__(self):\n",
    "        print('__repr__方法被调用')\n",
    "        return str(self.v)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [],
   "source": [
    "pv = PointwiseVector([1, 2, 3])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "__str__方法被调用\n",
      "[1, 2, 3]\n"
     ]
    }
   ],
   "source": [
    "print(pv)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "__str__方法被调用\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'[1, 2, 3]'"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "str(pv)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "__repr__方法被调用\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[1, 2, 3]"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pv"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "__repr__方法被调用\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'[1, 2, 3]'"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "repr(pv)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 6.1.4对象成员访问控制\n",
    "- `__`开头的属性具有一定的隐藏性，但并非真正的私有化\n",
    "- 特殊方法\n",
    "  - `__getattr__`：当试图访问一个对象中不存在的属性时触发该方法；\n",
    "  - `__getattribute__`：当试图访问对象属性（包括不存在的属性）时；\n",
    "  - `__setattr__`：当试图为对象绑定属性时触发该方法；\n",
    "  - `__delattr__`：当试图销毁对象属性时触发该方法。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "class TestAttrAccess:\n",
    "    def __getattr__(self, name):\n",
    "        print(f\"属性 {name} 不存在！\")\n",
    "        return None\n",
    "\n",
    "    def __setattr__(self, name, value):\n",
    "        print(\"设置了一个数值\")\n",
    "        self.__dict__[name] = value\n",
    "\n",
    "    def __delattr__(self, name):\n",
    "        print(\"删除了一个数值\")\n",
    "        del self.__dict__[name]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "taa = TestAttrAccess()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "属性 x 不存在！\n"
     ]
    }
   ],
   "source": [
    "taa.x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "设置了一个数值\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "10"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "taa.x = 10\n",
    "taa.x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "删除了一个数值\n",
      "属性 x 不存在！\n"
     ]
    }
   ],
   "source": [
    "del taa.x\n",
    "taa.x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- `__getattribute__`\n",
    "  - 只要试图访问对象的属性就会被触发\n",
    "  - 类中定义了`__getattribute__`方法时，`__getattr__`方法就会失效"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TestAttrAccess:\n",
    "    def __getattr__(self, name):\n",
    "        print(f\"属性 {name} 不存在！\")\n",
    "\n",
    "    def __getattribute__(self, name):\n",
    "        print(f'属性{name}被访问')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "属性x被访问\n"
     ]
    }
   ],
   "source": [
    "taa = TestAttrAccess()\n",
    "taa.x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 无限递归调用风险\n",
    "  - 在`__getattr__`中试图访问对象中不存在的属性时\n",
    "  - 在`__getattribute__`中试图访问对象中的任何属性时\n",
    "- 解决办法\n",
    "  - 通过访问父类属性\n",
    "  - 使用一个代理对象"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 6.1.5 描述器\n",
    "\n",
    "- 描述器是实现了`__get__`、`__set__`或`__delete__`三个方法中的一个或多个的类的实例\n",
    "- 描述器一般不会单独使用，最为常见的情况是将描述器作为其他类的属性\n",
    "\n",
    "- 描述的工作原理\n",
    "  - 默认情况下，在访问一个对象的属性时，解释器会依次查找该对象的`__dict__`属性、 所属类的`__dict__`属性、父类的`__dict__`属性......，直到找到所要访问的属性\n",
    "  - 当找到的属性是一个描述器时，并不会直接返回该描述器，而是会调 用描述器中的`__get__`、`__set__`或`__delete__`方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- `__get__(self, obj, type)`:当读取描述器中的值时触发，其中`obj`是描述器所属 的类的实例，`type`是描述器所属的类\n",
    "- `__set__(self, obj, value)`:当向描述器写入值时触发\n",
    "- `__delete__(self, obj)`:当销毁描述器时触发\n",
    "\n",
    "- 定义了 `__set__`或`__delete__`方法的对象称为数据描述器，仅定义了`__get__`方法 的描述器称为非数据描述器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "class Name:\n",
    "    def __init__(self, family_name, given_name):\n",
    "        self.family_name = family_name\n",
    "        self.given_name = given_name\n",
    "    \n",
    "    def __get__(self, obj, type):\n",
    "        return f'{self.given_name} {self.family_name}'\n",
    "    \n",
    "    def __set__(self, obj, value):\n",
    "        self.family_name = value[0]\n",
    "        self.given_name = value[1]\n",
    "    \n",
    "class Person:\n",
    "    name = Name('Rossum', 'Guido')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Guido Rossum'"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "p = Person()\n",
    "p.name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Bill Gates'"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "p.name = ('Gates', 'Bill')\n",
    "p.name"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 6.1.6 可调用对象\n",
    "\n",
    "- 可调用对象\n",
    "  - 函数\n",
    "  - labmda表达式\n",
    "  - 类\n",
    "  - 类方法\n",
    "- `__call__`\n",
    "  - 如果一个类中定义了特殊函数`__call__`，那么它的实例也是可调用对象"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "from functools import singledispatchmethod\n",
    "\n",
    "class Averager:\n",
    "    @singledispatchmethod\n",
    "    def read(self, data):\n",
    "        n = len(data)\n",
    "        self.value = sum(data)/n\n",
    "\n",
    "    @read.register(dict)\n",
    "    def _(self, data):\n",
    "        data = data.values()\n",
    "        n = len(data)\n",
    "        self.value = sum(data)/n\n",
    "\n",
    "    @read.register(str)\n",
    "    def _(self, data):\n",
    "        data = [float(i) for i in data.split(',')]\n",
    "        n = len(data)\n",
    "        self.value = sum(data)/n\n",
    "\n",
    "    def __call__(self, data):   # 可调用对象\n",
    "        self.read(data)\n",
    "        return self.value"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2.5"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "avg = Averager()\n",
    "avg([1, 2, 3, 4])\n",
    "\n",
    "avg('1, 2, 3, 4')\n",
    "\n",
    "\n",
    "Averager()('1, 2, 3, 4')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.6666666666666666"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 例：数据归一化\n",
    "\n",
    "class TestCall:\n",
    "    def __init__(self, xmax, xmin):\n",
    "        self.xmax, self.xmin = xmax, xmin\n",
    "\n",
    "    def __call__(self, x):\n",
    "        return (x - self.xmin)/(self.xmax - self.xmin)\n",
    "\n",
    "TestCall(180, 150)(170)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 6.1.7 容器\n",
    "\n",
    "- 容器\n",
    "  - 能够持有其他对象\n",
    "  - 具有读取、保存、删除元素、返回其中保存的元素的数量的方法\n",
    "- 容器特殊方法\n",
    "  -  `__getitem__`：使用`[]`读取保存在容器中的元素时触发；\n",
    "  -  `__setitem__`：修改容器中的元素时触发；\n",
    "  -  `__delitem__`：删除容器中的元素时触发；\n",
    "  -  `__len__` ：使用`len`函数获取容器中的元素数量时触发；\n",
    "  -  `__contains__`：使用`in`或`not in`判断元素是否包含在容器中；\n",
    "  -  `__reversed__(self)`：当容器中元素有序时，使用`reversed`函数反转元素的顺序时触发；"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "class MyList:\n",
    "    def __init__(self, values=None):\n",
    "        if values is None:\n",
    "            self.values = []\n",
    "        else:\n",
    "            self.values = list(values)\n",
    "            \n",
    "    def __getitem__(self, key):\n",
    "        return self.values[key]\n",
    "    \n",
    "    def __setitem__(self, key, value):\n",
    "        self.values[key] = value\n",
    "        \n",
    "    def __len__(self):\n",
    "        return len(self.values)\n",
    "    \n",
    "    def __delitem__(self, key):\n",
    "        del self.values[key]\n",
    "        \n",
    "    def __reversed__(self):\n",
    "        return reversed(self.values) \n",
    "    \n",
    "    def add(self, value):\n",
    "        self.values.append(value)\n",
    "        \n",
    "    def __str__(self):\n",
    "        return str(self.values)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<__main__.MyList at 0x7f9c207e5c70>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ml = MyList()\n",
    "ml"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<__main__.MyList at 0x7f9c207e5c70>"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ml.add(0)\n",
    "ml.add(1)\n",
    "ml"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "del ml[1]\n",
    "len(ml)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<__main__.MyList at 0x7f9c207e5c70>"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ml"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "0 in ml"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 6.1.8 迭代器与可迭代对象\n",
    "\n",
    "#### 迭代器\n",
    "\n",
    "- 迭代器协议\n",
    "  - `__iter__`：返回一个迭代器对象，由`iter`函数触发\n",
    "  - `__next__`：返回迭代器中的下一个元素，由`next`函数触发\n",
    "- `StopIteration`异常\n",
    "  - 迭代器在迭代的过程中，遇到`StopIteration`异常表示迭代过程结束"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "class Fibonacci:\n",
    "    def __init__(self):\n",
    "        self.v1 = 0\n",
    "        self.v2 = 1\n",
    "\n",
    "    def __iter__(self):\n",
    "        return self\n",
    "\n",
    "    def __next__(self):\n",
    "        value = self.v2\n",
    "        if value >= 100:\n",
    "            raise StopIteration\n",
    "        self.v1, self.v2 = self.v2, self.v1 + self.v2\n",
    "        return value"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fb = Fibonacci()\n",
    "next(fb)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]\n"
     ]
    }
   ],
   "source": [
    "fb = Fibonacci()\n",
    "print(list(fb))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### 可迭代对象\n",
    "\n",
    "- 能够被迭代的对象称为可迭代对象\n",
    "  - 可用于`for`循环、各种推导式、元组拆包、序列解包、参数分配等操作\n",
    "- 迭代器是可迭代对象的一种"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TestIter:\n",
    "    def __init__(self):\n",
    "        self.values = [1, 2, 3, 4, 5]\n",
    "\n",
    "    def __getitem__(self, key):\n",
    "        return self.values[key]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n",
      "4\n",
      "5\n"
     ]
    }
   ],
   "source": [
    "ti = TestIter()\n",
    "for n in ti:\n",
    "    print(n)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- `ti`确实不是迭代器，它能够被迭代的原因是实现了`__getitem__`方法\n",
    "- 运行过程\n",
    "  - Python解释器会自动调用`iter(obj)`\n",
    "  - `iter`函数首先检查`obj`中是否包含`__iter__`方法\n",
    "    - 如果是，则调用它并获取一个迭代器\n",
    "    - 如果`obj`中没有`__iter__`方法，则进一步检查它是否包含`__getitem__`方法\n",
    "      - 如果是，则尝试按整数索引获取`obj`中的元素，并基于这些元素创建出一个可迭代对象\n",
    "      - 如果`obj`中不包含`__getitem__`方法，返回错误\"TypeError: 'obj' object is not iterable\"\n",
    "- 迭代器与可迭代对象的重要区别\n",
    "  - 迭代器只能使用一次，经过一次迭代`next`函数已经遇到`StopIteration`异常，迭代器不会自动重置\n",
    "  - 可迭代对象则可以重复被迭代，每一次迭代都会重新创建一个新的可迭代对象。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 6.2 生成器\n",
    "\n",
    "### 6.2.1 生成器的创建\n",
    "#### 生成器函数\n",
    "\n",
    "- `yield`\n",
    "  - 在函数中返回一个数值\n",
    "  - `yield`的值不是通过函数调用返回的，而是返回到迭代过程之中\n",
    "- 使用了`yield`返回值的函数称为生成器函数\n",
    "  - 一个函数中一旦使用了`yield`关键字，它就不再是一个普通的函数\n",
    "  - 即便中其中包含了`return`语句，在调用的时候也不会返回值，而是返回一个生成器对象\n",
    "- 生成器函数可被看作是生成器工厂"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "def gen_fun():\n",
    "    yield 0\n",
    "    return 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "generator"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "g = gen_fun()\n",
    "type(g)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 生成器是一种特殊的迭代器，可利用`next`函数获取`yield`返回的数值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "ename": "StopIteration",
     "evalue": "1",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mStopIteration\u001b[0m                             Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-12-12844bda11d7>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0mg\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mgen_fun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      2\u001b[0m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mStopIteration\u001b[0m: 1"
     ]
    }
   ],
   "source": [
    "g = gen_fun()\n",
    "next(g)\n",
    "next(g)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- `yield`语句\n",
    "  - 函数中可以多个`yield`语句或者多次执行`yield`语句，每次执行`yield`语句都会返回一个值\n",
    "  - `yield`语句被执行并返回值后，生成器就被阻塞掉，不会自动继续运行，直到下一次调用`next`函数来激活\n",
    "  - 当生成器函数中没有`yield`语句可以被再次执行时，执行`next`会抛出`StopIteration`异常"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "def gen_fun(n):\n",
    "    for i in range(n):\n",
    "        print(f'返回{i}')\n",
    "        yield i"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "返回0\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "g = gen_fun(2)\n",
    "next(g)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "返回1\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "next(g)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "ename": "StopIteration",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mStopIteration\u001b[0m                             Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-13-e734f8aca5ac>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mStopIteration\u001b[0m: "
     ]
    }
   ],
   "source": [
    "next(g)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 生成器可以像其他可迭代对象一样使用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "返回0\n",
      "0\n",
      "返回1\n",
      "1\n",
      "返回2\n",
      "2\n",
      "返回3\n",
      "3\n",
      "返回4\n",
      "4\n"
     ]
    }
   ],
   "source": [
    "g = gen_fun(5)\n",
    "for i in g:\n",
    "   print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 惰性计算\n",
    "  - 生成器中并不持有全部迭代元素，每次`next`执行临时生成一个元素并返回\n",
    "  - 原因\n",
    "    - 每次调用`yield`语句返回值后都会被阻塞"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### 生成器推导式\n",
    "\n",
    "- 生成器推导式与生成器函数的作用相同，都是返回一个生成器，只不过提供了一种更加便捷的语法\n",
    "- 生成器函数 vs 生成器推导式\n",
    "  - 当生成器要实现的功能比较复杂时最好使用生成器函数\n",
    "  - 当功能仅通过一个表达式就能够实现时选择生成器推导式更合适"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<generator object <genexpr> at 0x10a4ff7b0>"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "g = (i**2 for i in [1, 2])\n",
    "g"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "next(g)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "next(g)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "ename": "StopIteration",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mStopIteration\u001b[0m                             Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-18-e734f8aca5ac>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mStopIteration\u001b[0m: "
     ]
    }
   ],
   "source": [
    "next(g)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### `yield from`\n",
    "\n",
    "- 为生成器函数依次返回可迭代对象中的元素，从而替代循环语句，使得代码更加简洁有效\n",
    "- 包含了复杂的异常处理的工作，可用于协程之中实现复杂的功能"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "def gen_fun(iters):\n",
    "    for it in iters:\n",
    "        yield from it"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "g = gen_fun([[1, 2, 3], ['a', 'b', 'c']])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 2, 3, 'a', 'b', 'c']"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list(g)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 6.2.2 生成器与迭代器\n",
    "\n",
    "- 将`__iter__`作为一个生成器函数来使用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "class GenIter:\n",
    "    def __init__(self, values):\n",
    "        self.values = values\n",
    "    \n",
    "    def __iter__(self):\n",
    "        # for v in self.values:\n",
    "        #     yield v\n",
    "        yield from self.values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n"
     ]
    }
   ],
   "source": [
    "gi = GenIter([1, 2, 3])\n",
    "for n in gi:\n",
    "   print(n)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 6.3 类装饰器\n",
    "### 6.3.1 修饰方法的装饰器\n",
    "\n",
    "- 与函数装饰器相同，但需要处理方法特殊参数`self`或`cls`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "def add_property(method):\n",
    "    def wrapper(self):\n",
    "        print(\"添加一个属性\")\n",
    "        self.new_property = 0\n",
    "        result = method(self)\n",
    "        del self.new_property\n",
    "        print(\"删除属性\")\n",
    "        return result\n",
    "    return wrapper"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TestMethodDec:\n",
    "    @add_property\n",
    "    def method(self):\n",
    "        print(self.new_property)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "添加一个属性\n",
      "0\n",
      "删除属性\n"
     ]
    }
   ],
   "source": [
    "tm = TestMethodDec()\n",
    "tm.method()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 带参数的方法装饰器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "def add_property(prop_name, value):\n",
    "    def decorator(method):\n",
    "        def wrapper(self, *args, **kwargs):\n",
    "            print(f\"添加属性{prop_name}\")\n",
    "            self.__dict__[prop_name] = value\n",
    "            result = method(self, *args, **kwargs)\n",
    "            del self.__dict__[prop_name]\n",
    "            print(f\"删除属性{prop_name}\")\n",
    "            return result\n",
    "        return wrapper\n",
    "    return decorator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TestMethodDec:\n",
    "    @add_property('new_property', 100)\n",
    "    def method(self):\n",
    "        print(self.new_property)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "添加属性new_property\n",
      "100\n",
      "删除属性new_property\n"
     ]
    }
   ],
   "source": [
    "tm = TestMethodDec()\n",
    "tm.method()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 在不对类或实例进行操作时，可定义即能用于函数又能用于方法的装饰器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import time\n",
    "\n",
    "def run_time(fun):\n",
    "    def wrapper(*args, **kwargs):\n",
    "        start = time.time()\n",
    "        result = fun(*args, **kwargs)\n",
    "        end = time.time()\n",
    "        print(f'函数{fun.__name__}的执行时间为{(end-start):.4}秒')\n",
    "        return result\n",
    "    return wrapper"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 6.3.2 修饰类的装饰器\n",
    "\n",
    "- 原理\n",
    "  - 在修饰类的装饰器中定义一个类，替换掉被修饰的类\n",
    "  - 为了保留被修饰类的原有功能，通常需要实例化一个被修饰类的对象，将该对象作为新类的属性，通过属性代理访问的方式来实现被修饰类的功能"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "def class_dec(class_deced):\n",
    "    class Inner:\n",
    "        def __init__(self, *args, **kwargs):\n",
    "            self.class_obj = class_deced(*args, **kwargs)\n",
    "        def method(self):\n",
    "            print(\"执行装饰器中类的方法\")\n",
    "            return self.class_obj.method()\n",
    "    return Inner"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "@class_dec\n",
    "class TestClassDec:\n",
    "    def method(self):\n",
    "        print(\"执行被修饰器的方法\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "执行装饰器中类的方法\n",
      "执行被修饰器的方法\n"
     ]
    }
   ],
   "source": [
    "tm = TestClassDec()\n",
    "tm.method()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 更加灵活的方式\n",
    "  - `getattr(obj, prop_name)`函数的作用是返回`obj`的名为`prop_name`的的属性"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def class_dec(class_deced):\n",
    "    class Inner:\n",
    "        def __init__(self, *args, **kwargs):\n",
    "            self.class_obj = class_deced(*args, **kwargs)\n",
    "        def __getattr__(self, prop_name):\n",
    "            return getattr(self.class_obj, prop_name)\n",
    "    return Inner"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 6.3.3 基于类的装饰器*\n",
    "\n",
    "- 利用类来实现装饰器\n",
    "  - 修饰函数\n",
    "  - 修饰方法\n",
    "  - 修饰类"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### 修饰函数类装饰器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "import time\n",
    "\n",
    "class RunTime():\n",
    "    def __init__(self, fun):\n",
    "        self.fun = fun\n",
    "\n",
    "    def __call__(self):\n",
    "        start = time.time()\n",
    "        result = self.fun()\n",
    "        end = time.time()\n",
    "        print(f'函数{self.fun.__name__}的执行时间为{(end-start):.4}秒')\n",
    "        return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "@RunTime\n",
    "def test_fun():\n",
    "    time.sleep(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<__main__.RunTime at 0x10eb444c0>"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "test_fun"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "函数test_fun的执行时间为1.005秒\n"
     ]
    }
   ],
   "source": [
    "test_fun()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 保留元信息\n",
    "  - 利用`wraps`函数，或者功能相似的`update_wrapper`函数来实现"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "from functools import update_wrapper\n",
    "\n",
    "class ClassDec():\n",
    "    def __init__(self, fun):\n",
    "        self.fun = fun\n",
    "        update_wrapper(self, fun)\n",
    "\n",
    "    def __call__(self):\n",
    "        return self.fun()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "@ClassDec\n",
    "def test_fun():\n",
    "    pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<__main__.ClassDec at 0x10fa546a0>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "test_fun.__name__\n",
    "test_fun"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### 修饰方法的类装饰器\n",
    "- 在装饰器类的`__call__`方法处理特殊参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TestDec:\n",
    "    @ClassDec\n",
    "    def method(self):\n",
    "        pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "method() missing 1 required positional argument: 'self'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-17-9e662c8506d2>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0mtd\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mTestDec\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mtd\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmethod\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m<ipython-input-12-1a658fa139b3>\u001b[0m in \u001b[0;36m__call__\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m      7\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      8\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0m__call__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 9\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m: method() missing 1 required positional argument: 'self'"
     ]
    }
   ],
   "source": [
    "td = TestDec()\n",
    "td.method()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 在`__call__`中调用被修饰方法时，传入`self`即可，即`self.fun(self)`\n",
    "   - 该装饰器无法再用于函数之上。 \n",
    "- 在装饰器中同时实现`__call__`方法和`__get__`方法使其即能修饰方法又能修饰函数\n",
    "   - `types.MethodType`的作用是将`self`作为方法绑定至`obj`实例之上"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "import types\n",
    "\n",
    "class ClassDec():\n",
    "    def __init__(self, fun):\n",
    "        self.fun = fun\n",
    "\n",
    "    def __call__(self, *args, **kwargs):\n",
    "        print('执行__call__')\n",
    "        return self.fun(*args, **kwargs)\n",
    "\n",
    "    def __get__(self, obj, cls):\n",
    "        print('执行__get__')\n",
    "        print(obj)\n",
    "        print(cls)\n",
    "        return types.MethodType(self, obj)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "@ClassDec\n",
    "def fun():\n",
    "    print('执行被修饰函数')\n",
    "\n",
    "class TestDec:\n",
    "    @ClassDec\n",
    "    def method(self):\n",
    "        print('执行被修饰方法')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "执行__call__\n",
      "执行被修饰函数\n"
     ]
    }
   ],
   "source": [
    "fun()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "执行__get__\n",
      "<__main__.TestDec object at 0x10ebf4160>\n",
      "<class '__main__.TestDec'>\n",
      "执行__call__\n",
      "执行被修饰方法\n"
     ]
    }
   ],
   "source": [
    "td = TestDec()\n",
    "td.method()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 实现原理\n",
    "  - 实现`__get__`方法之后，装饰器成为一个描述器\n",
    "  - `TestDec`类中被修饰的`method`方法被替换为一个同名的描述器\n",
    "  - 在访问`td`对象的`method`方法时，会进一步调用描述器的`__get__`方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### 修饰类的类装饰器\n",
    "\n",
    "- 装饰器`__call__`方法中创建一个被修饰类的实例并返回"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "class ClassDec:\n",
    "    def __init__(self, dec_cls):\n",
    "        self.dec_cls = dec_cls\n",
    "\n",
    "    def __call__(self, *args, **kwargs):\n",
    "        print(f'实例化一个{self.dec_cls}对象')\n",
    "        return self.dec_cls(*args, **kwargs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "@ClassDec\n",
    "class TestDec:\n",
    "    def method(self):\n",
    "        print('执行方法')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "实例化一个<class '__main__.TestDec'>对象\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<__main__.TestDec at 0x10fa54ca0>"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "td = TestDec()\n",
    "td"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 6.4 抽象基类*\n",
    "### 6.4.1 抽象基类的概念\n",
    "\n",
    "- 抽象类与抽象方法\n",
    "- 抽象类的主要作用有\n",
    "  - 提高软件的灵活性\n",
    "  - 提高代码规范程序\n",
    "  - 便于软件的设计\n",
    "  - 提供一类实例共性方法的统一实现\n",
    "- Python中的抽象基类\n",
    "  - 通常不需要自定义抽象基类，大部分情况下内置的抽象基类就能够满足需要"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 6.4.2 抽象基类的应用\n",
    "\n",
    "- 方法\n",
    "  - 派生抽象基类\n",
    "  - 注册虚拟子类"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### 派生抽象基类"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from collections import abc\n",
    "\n",
    "class TestAbc1(abc.MutableSequence):\n",
    "    def __init__(self, values):\n",
    "        self._values = list(values)\n",
    "\n",
    "    def __len__(self):\n",
    "        return len(self._values)\n",
    "\n",
    "    def __getitem__(self, index):\n",
    "        return self._values[index]\n",
    "\n",
    "    def __setitem__(self, index, value):\n",
    "        self._values[index] = value\n",
    "\n",
    "    def __delitem__(self, index):\n",
    "        del self._values[index]\n",
    "\n",
    "    def insert(self, index, value):\n",
    "        self._values.insert(index, value)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TestAbc2(abc.MutableSequence):\n",
    "    pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ta1 = TestAbc1([1, 2, 3])\n",
    "len(ta1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 抽象基类与鸭子类型\n",
    "  - 抽象方法强制实现\n",
    "  - 能够使用`isinsance`和`issubclass`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TestAbc3:\n",
    "    def __init__(self, values):\n",
    "        self._values = list(values)\n",
    "\n",
    "    def __len__(self):\n",
    "        return len(self._values)\n",
    "\n",
    "    def __getitem__(self, index):\n",
    "        return self._values[index]\n",
    "\n",
    "    def __setitem__(self, index, value):\n",
    "        self._values[index] = value\n",
    "\n",
    "    def __delitem__(self, index):\n",
    "        del self._values[index]\n",
    "\n",
    "    def insert(self, index, value):\n",
    "        self._values.insert(index, value)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "isinstance(ta1, abc.MutableSequence)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ta3 = TestAbc3([1, 2, 3])\n",
    "isinstance(ta3, abc.MutableSequence)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 某些情况下即便没有继承抽象基类，使用`isinstance`也会返回`True`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "from collections import abc\n",
    "\n",
    "class TestABC:\n",
    "    def __init__(self):\n",
    "        self.num = 0\n",
    "\n",
    "    def __len__(self):\n",
    "        return self.num"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ta = TestABC()\n",
    "isinstance(ta, abc.Sized)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 原因\n",
    "  - `abc.Sized`抽象基类中实现了一个特殊方法`__subclasshook__`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "@classmethod\n",
    "def __subclasshook__(cls, C):\n",
    "    if cls is Sized:\n",
    "        if any(\"__len__\" in B.__dict__ for B in C.mro__):\n",
    "            return True\n",
    "    return NotImplemented"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### 注册虚拟子类\n",
    "\n",
    "- 抽象基类的`register`方法或`register`装饰器\n",
    "- 特点\n",
    "  - 注册虚拟子类时，Python不会检查抽象方法是否被实现"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "from collections import abc\n",
    "\n",
    "@abc.MutableSequence.register                # 使用装饰器注册虚拟子类\n",
    "class TestAbc3:\n",
    "    def __init__(self, values):\n",
    "        self._values = list(values)\n",
    "    def __len__(self):\n",
    "        return len(self._values)\n",
    "    def __getitem__(self, index):\n",
    "        return self._values[index]\n",
    "    def __setitem__(self, index, value):\n",
    "        self._values[index] = value\n",
    "    def __delitem__(self, index):\n",
    "        del self._values[index]\n",
    "    def insert(self, index, value):\n",
    "        self._values.insert(index, value)\n",
    "# abc.MutableSequence.register(TestAbc3)      # 使用函数注册虚拟子类"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tb3 = TestAbc3([1, 2, 3])\n",
    "isinstance(tb3, abc.MutableSequence)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "#### 常用内置抽象基类\n",
    "\n",
    "- `collections.abc`模块\n",
    "\n",
    "| 抽象基类          | 继承自                            | 抽象方法                                                     | Mixin 方法                                                   |\n",
    "| :---------------- | :-------------------------------- | :----------------------------------------------------------- | :----------------------------------------------------------- |\n",
    "| `Container`       |                                   | `__contains__`                                               |                                                              |\n",
    "| `Hashable`        |                                   | `__hash__`                                                   |                                                              |\n",
    "| `Iterable`        |                                   | `__iter__`                                                   |                                                              |\n",
    "| `Iterator`        | `Iterable`                        | `__next__`                                                   | `__iter__`                                                   |\n",
    "| `Reversible`      | `Iterable`                        | `__reversed__`                                               |                                                              |\n",
    "| `Generator`       | `Iterator`                        | `send`, `throw`                                              | `close`, `__iter__`,  `__next__`                             |\n",
    "| `Sized`           |                                   | `__len__`                                                    |                                                              |\n",
    "| `Callable`        |                                   | `__call__`                                                   |                                                              |\n",
    "| `Collection`      | `Sized`, `Iterable`, `Container ` | `__contains__`, `__iter__`, `__len__`                        |                                                              |\n",
    "| `Sequence`        | `Reversible`,`Collection`         | `__getitem__`, `__len__`                                     | `__contains__`,  `__iter__`, `__reversed__`,  `index`, `count` |\n",
    "| `MutableSequence` | `Sequence`                        | `__getitem__`, `__setitem__`,  `__delitem__`,  `__len__`,  `insert` | 继承自 `Sequence` 的方法，以及 `append`,  `reverse`, `extend`,  `pop`, `remove`， `__iadd__` |\n",
    "| `ByteString`      | `Sequence`                        | `__getitem__`, `__len__`                                     | 继承自 `Sequence`  的方法                                    |\n",
    "| `Set`             | `Collection`                      | `__contains__`,  `__iter__`,`__len__`                        | `__le__`, `__lt__`, `__eq__`,  `__ne__`, `__gt__`,  `__ge__`, `__and__`,   `__or__`,`__sub__`, `__xor__`,   `isdisjoint` |\n",
    "| `MutableSet`      | `Set`                             | `__contains__`,  `__iter__`, `__len__`,  `add`, `discard`    | 继承自  `Set` 的方法以及 `clear`,  `pop`, `remove`,  `__ior__`,  `__iand__`, `__ixor__`, `__isub__` |\n",
    "| `Mapping`         | `Collection`                      | `__getitem__`, `__iter__`, `__len__`                         | `__contains__`, `keys`, `items`,  `values`, `get`, `__eq__`, and `__ne__` |\n",
    "| `MutableMapping`  | `Mapping`                         | `__getitem__`, `__setitem__`, `__delitem__`, `__iter__`, `__len__` | 继承自 `Mapping`  的方法以及 `pop`, `popitem`, `clear`, `update`，和 `setdefault` |\n",
    "| `MappingView`     | `Sized`                           |                                                              | `__len__`                                                    |\n",
    "| `ItemsView`       | `MappingView` , `Set`             |                                                              | `__contains__`, `__iter__`                                   |\n",
    "| `KeysView`        | `MappingView`  , `Set `           |                                                              | `__contains__`, `__iter__`                                   |\n",
    "| `ValuesView`      | `MappingView`  , `Collection`     |                                                              | `__contains__`, `__iter__`                                   |\n",
    "| `Awaitable`       |                                   | `__await__`                                                  |                                                              |\n",
    "| `Coroutine`       | `Awaitable`                       | `send`, `throw`                                              | `close`                                                      |\n",
    "| `AsyncIterable`   |                                   | `__aiter__`                                                  |                                                              |\n",
    "| `AsyncIterator`   | `AsyncIterable`                   | `__anext__`                                                  | `__aiter__`                                                  |\n",
    "| `AsyncGenerator`  | `AsyncIterator`                   | `asend`, `athrow`                                            | `aclose`, `__aiter__`, `__anext__`                           |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "### 6.4.3 自定义抽象基类\n",
    "\n",
    "- 自定义抽象基类需要继承`abc.ABC`类\n",
    "- 使用`abc.abstractmethod`装饰器将一个方法声明为抽象方法\n",
    "  - `abstractmethod`装饰器也可以和其他装饰器叠加使用，如`staticmethod`、`classmethod`，不过`abstractmethod`必须是最内层装饰器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from collections import abc\n",
    "\n",
    "class Moto(abc.ABC):\n",
    "    @abc.abstractmethod\n",
    "    def run(self, speed):\n",
    "        \"\"\"行驶\"\"\"\n",
    "\n",
    "    @abc.abstractmethod\n",
    "    def refueling(self, litre):\n",
    "        \"\"\"加油\"\"\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 6.5 元类*\n",
    "### 6.5.1 Python类的特征\n",
    "\n",
    "#### 类的一等对象特征\n",
    "\n",
    "- Python中的类\n",
    "  - 可以被赋值给变量\n",
    "  - 作为参数传递给函数\n",
    "  - 可以作为函数的返回值\n",
    "  - 能够在程序运行期间动态创建"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "class TestClass:\n",
    "    pass\n",
    "\n",
    "def get_class():\n",
    "    class TestClass:\n",
    "        pass\n",
    "    return TestClass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<__main__.TestClass at 0x1119ec670>"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Test = TestClass       # 赋值给变量\n",
    "t = Test()\n",
    "t"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<__main__.TestClass at 0x111aa10a0>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "lst = []\n",
    "lst.append(TestClass)  # 放入容器之中\n",
    "lst[0]()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<__main__.get_class.<locals>.TestClass at 0x1119ec6d0>"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "get_class()()   "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### 类的类型\n",
    "\n",
    "- 即然Python中的类也是对象，那么它们与其他的对象类似，也需要有一个“类”来描述和创建\n",
    "- 元类\n",
    "  - 用于创建类的“类”称为元类\n",
    "  - 类是元类的实例，元类是比类更高一级的抽象"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "__main__.TestClass"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tc = TestClass()\n",
    "type(tc)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "__main__.TestClass"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tc.__class__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "type"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "type(TestClass)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "type"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "TestClass.__class__"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 不只是自定义的类，如果没有指定元类，默认情况下Python中所有类的类型都是`type`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "type"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list.__class__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "type"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tuple.__class__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "type"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "set.__class__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "type"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dict.__class__"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### 类的动态创建\n",
    "\n",
    "- `get_class`函数每一次调用它都会动态地创建出一个新的类\n",
    "- 使用`type`函数能够更加灵活地动态创建类，它需要三个参数\n",
    "  - `name`：字符串，用于指定类的名字；\n",
    "  - `bases`：元组，用于指定基类，当为空元组时表示使用默认基类`object`；\n",
    "  - `dict`：字典，用于指定类的属性和方法，空字典表示没有属性或方法。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<__main__.TestClass at 0x111aa1910>"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def m1(self):\n",
    "    print(\"执行m1方法\")\n",
    "test_class = type('TestClass', (), {'x': 1, 'm1': m1})\n",
    "test_class()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "执行m1方法\n"
     ]
    }
   ],
   "source": [
    "test_class().m1()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 静态方法与类方法\n",
    "  - 只需要像普通的类定义中那样使用`classmethod`或`staticmethod`装饰器修饰函数属性即可\n",
    "- python中`type`的作用\n",
    "  - 作为函数来判断数据的类型\n",
    "  - 是所有元类的默认基类，所有的元类都必须派生自`type`\n",
    "  - 可以用于动态创建类"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 6.5.2 元类的定义与使用\n",
    "#### 自定义元类\n",
    "\n",
    "- Python中所有的元类都必须是`type`的派生类\n",
    "- 在类定义的时候，如果指定父类为`type`或者基它元类，那么这个类就是一个元类\n",
    "- 元类的定义与普通的类基本一致，可以使用一些特殊方法对元类进行定制\n",
    "- `__new__`方法\n",
    "  - 四个参数 `cls`、`name`、`bases`、` dict`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "class LowerAttr(type):\n",
    "    def __new__(cls, name, bases, attrs):\n",
    "        new_attrs = {}\n",
    "        for attr in attrs:\n",
    "            if attr.startswith('__') and attr.endswith('__'):\n",
    "                new_attrs[attr] = attrs[attr]\n",
    "            else:\n",
    "                new_attrs[attr.lower()] = attrs[attr]\n",
    "        return super().__new__(cls, name, bases, new_attrs)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### 使用元类"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Test(metaclass=LowerAttr):\n",
    "    def METHOD1(self):\n",
    "        print('METHOD1') "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "'Test' object has no attribute 'METHOD1'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-21-b4d216c52d52>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0mt\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mTest\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mt\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mMETHOD1\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m: 'Test' object has no attribute 'METHOD1'"
     ]
    }
   ],
   "source": [
    "t = Test()\n",
    "t.METHOD1()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "METHOD1\n"
     ]
    }
   ],
   "source": [
    "t.method1()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### 类的创建过程\n",
    "\n",
    "- 类创建过程\n",
    "  - Python解释器解析类的代码\n",
    "  - 将类的名称、基类元组、属性字典传递给元类的`__new__`方法\n",
    "  - `__new__`方法根据传入的参数调用`type`来创建类\n",
    "- 元类的使用\n",
    "  - 当前类指定了元类，则用它来创建类\n",
    "  - 如果当前类没有指定元类则进一步遍历检查基类中是否指定元类\n",
    "  - 如果基类中也没有指定元类，则使用默认的`type`来创建类"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 6.5.3 元类的应用实例\n",
    "\n",
    "#### 应用场景\n",
    "\n",
    "- 元类是Python中最为复杂的内容之一，而且它的部分功能也可以使用装饰器或者类的定制来实现\n",
    "  - 在绝大多数的Python编程任务中不需要使用元类\n",
    "- 元类最常用的应用场景是构建应用程序的API或编程框架"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### 利用元类实现ORM"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Field:\n",
    "    def __init__(self, name, column_type):\n",
    "        self.name = name\n",
    "        self.column_type = column_type\n",
    "\n",
    "    def __str__(self):\n",
    "        return f'{self.__class__.__name__}:{self.name}'\n",
    "\n",
    "\n",
    "class StrField(Field):\n",
    "    def __init__(self, name):\n",
    "        super().__init__(name, 'varchar(50)')\n",
    "\n",
    "\n",
    "class IntField(Field):\n",
    "    def __init__(self, name):\n",
    "        super().__init__(name, 'int')\n",
    "\n",
    "\n",
    "class ModelMetaclass(type):\n",
    "    def __new__(cls, name, bases, attrs):\n",
    "        if name == 'Model':\n",
    "            return type.__new__(cls, name, bases, attrs)\n",
    "        mappings = dict()\n",
    "        for k, v in attrs.items():\n",
    "            if isinstance(v, Field):\n",
    "                mappings[k] = v\n",
    "        for k in mappings:\n",
    "            attrs.pop(k)\n",
    "        attrs['__mappings__'] = mappings\n",
    "        attrs['__table__'] = name\n",
    "        return type.__new__(cls, name, bases, attrs)\n",
    "\n",
    "\n",
    "class Model(dict, metaclass=ModelMetaclass):\n",
    "    def __getattr__(self, key):\n",
    "        return self.get(key, None)\n",
    "\n",
    "    def __setattr__(self, key, value):\n",
    "        self[key] = value\n",
    "\n",
    "    def save(self):\n",
    "        fields = []\n",
    "        params = []\n",
    "        args = []\n",
    "        for k, v in self.__mappings__.items():\n",
    "            fields.append(v.name)\n",
    "            params.append('?')\n",
    "            args.append(getattr(self, k, None))\n",
    "        sql = f'insert into {self.__table__} ({\",\".join(fields)}) values ({\",\".join(params)})'\n",
    "        print(sql, tuple(args))\n",
    "\n",
    "\n",
    "class User(Model):\n",
    "    # 定义类的属性到列的映射：\n",
    "    id = IntField('id')\n",
    "    name = StrField('username')\n",
    "    password = StrField('password')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "insert into User (id,username,password) values (?,?,?) (1, '张三', '123456')\n",
      "insert into User (id,username,password) values (?,?,?) (2, '李四', '123456')\n"
     ]
    }
   ],
   "source": [
    "# 创建一个实例：\n",
    "u = User(id=1, name='张三', password='123456')\n",
    "# 保存到数据库：\n",
    "u.save()\n",
    "\n",
    "u = User(id=2, name='李四', password='123456')\n",
    "u.save()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## 6.6 对象序列化*\n",
    "\n",
    "\n",
    "- 序列化\n",
    "  - 对象序列化(Serialization)也称为对象持久化，是指将内存中的对象转换为数据流， 能够存储在文件之中或者通过网络进行传输\n",
    "- 反序列化\n",
    "  - 对象反序列化是指将二进制字节 数据流恢复重建为 Python 对象"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 6.6.1 pickle\n",
    "\n",
    "- 对象序列化和反序列化最常用的工具。常用函数包括：\n",
    "  - `dump(obj, file, protocol=None)`:将对象`obj`序列化为二进制数据，并写入打开的文件对象`file`之中\n",
    "  - `load(file)`:从打开的文件对象`file`中加载序列化对象，反序列化重建对象\n",
    "  - `dumps(obj, protocol=None)`:将对象`obj`序列化为二进制数据\n",
    "  - `loads(data)`:对序列化之后的二进制数据进行反序列化操作，重建对象"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 绝大多数Python数据类型都可以被序列化和反序列化，包括\n",
    "  - `Non`e、 布尔类型(`True`和`False`)、字符串(`str`)、字节串(`byte`)、字节数组(`bytearray`)\n",
    "  - 全局函数和类\n",
    "  - `__dict__`属性或`__getstate__`方法返回值可以被可被序列化的对象\n",
    "  - 元素都为可序列化对象的列表、元组、集合和字典"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### 一般数据类型的序列化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pickle\n",
    "\n",
    "# 待序列化数据\n",
    "data = {\n",
    "    'list': [1, 2.0, 3, 4+5j],\n",
    "    'tuple': (\"字符串数据\", b\"byte string\"),\n",
    "    'set': {None, True, False}\n",
    "}\n",
    "\n",
    "# 序列化\n",
    "with open('data.pickle', 'wb') as f:\n",
    "    pickle.dump(data, f)\n",
    "\n",
    "# 反序列化\n",
    "with open('data.pickle', 'rb') as f:\n",
    "    data = pickle.load(f)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### 函数、类和实例的序列化\n",
    "- 在序列化时，只有函数名和类名被序列化，而函数体及类体（包括类数据）不会被序列化\n",
    "- 在对函数和类进行反序列化的时候，它们的定义必须是可见的"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "- 函数和类的序列化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pickle\n",
    "\n",
    "def test_fun():\n",
    "    return 'Hello Pickle'\n",
    "\n",
    "class TestClass:\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "fun_pkl = pickle.dumps(test_fun) \n",
    "class_pkl = pickle.dumps(TestClass) \n",
    "fun = pickle.loads(fun_pkl)\n",
    "fun()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "Can't get attribute 'test_fun' on <module '__main__'>",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-4-58bb2403b666>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      3\u001b[0m \u001b[0;32mdel\u001b[0m \u001b[0mtest_fun\u001b[0m                          \u001b[0;31m# 删除函数定义\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      4\u001b[0m \u001b[0;32mdel\u001b[0m \u001b[0mTestClass\u001b[0m                         \u001b[0;31m# 函数类定义\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0mfun\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mpickle\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mloads\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfun_pkl\u001b[0m\u001b[0;34m)\u001b[0m           \u001b[0;31m# 再次反序列化函数\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m: Can't get attribute 'test_fun' on <module '__main__'>"
     ]
    }
   ],
   "source": [
    "test_class = pickle.loads(class_pkl)  # 类反序列化\n",
    "obj = test_class()\n",
    "del test_fun                          # 删除函数定义\n",
    "del TestClass                         # 函数类定义\n",
    "fun = pickle.loads(fun_pkl)           # 再次反序列化函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "Can't get attribute 'TestClass' on <module '__main__'>",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-5-d8daf5b93233>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mtest_class\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mpickle\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mloads\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mclass_pkl\u001b[0m\u001b[0;34m)\u001b[0m  \u001b[0;31m# 再次反序列化类\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m: Can't get attribute 'TestClass' on <module '__main__'>"
     ]
    }
   ],
   "source": [
    "test_class = pickle.loads(class_pkl)  # 再次反序列化类"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### 实例的序列化\n",
    "  - 实例在序列化的时候，只会保存实例中的属性数据，实例所属的类同样不会被序列化\n",
    "  - 在反序列化时，类也必须也是可见的\n",
    "  - 反序列化时不会调用`__init__`方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pickle\n",
    "\n",
    "class TestClass:\n",
    "    attr_cls = 1\n",
    "    def __init__(self):\n",
    "        self.attr_obj = 2\n",
    "\n",
    "obj = TestClass()\n",
    "obj.attr_obj = 3\n",
    "obj_pkl = pickle.dumps(obj)     # 实例序列化\n",
    "\n",
    "del obj\n",
    "obj = pickle.loads(obj_pkl)     # 实例反序列化\n",
    "\n",
    "print(obj.attr_cls)\n",
    "print(obj.attr_obj)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 6.6.2 copyreg\n",
    "\n",
    "- copyreg的作用是注册能够在序列化和反序列化过程中被调用的函数，用于控制序列化和反序列化的过程\n",
    "  - 在实际应用中往往会遇到软件升级的情况。升级之后，加载数据时可能会遇到旧版软件的反序列化数据，可能会出现不兼容的情况。`copyreg`模块通过为目标类型注册约函数和重构函数来控制反序列化过程，从而实现版本兼容"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pickle\n",
    "import copyreg\n",
    "\n",
    "class User:                                     # 旧版User类\n",
    "    def __init__(self, name, age):\n",
    "        self.name = name\n",
    "        self.age = age\n",
    "\n",
    "def unpickle_fun(obj_data):                     # 重建被序列化的对象\n",
    "    print('reconstructing')\n",
    "    return User(**obj_data)\n",
    "\n",
    "def pickle_fun(obj):                            # 在序列化之前调用\n",
    "    print('before pickling')\n",
    "    return unpickle_fun, (obj.__dict__,)\n",
    "\n",
    "copyreg.pickle(User, pickle_fun, unpickle_fun)  # 注册归约函数和重构函数\n",
    "\n",
    "user = User('张三', 20)\n",
    "user_pkl = pickle.dumps(user)                   # 序列化旧版User的对象\n",
    "\n",
    "del User\n",
    "\n",
    "class User:                                     # 新版User类\n",
    "    def __init__(self, name, age, email='common@test.email'):\n",
    "        self.name = name\n",
    "        self.age = age\n",
    "        self.email = email\n",
    "\n",
    "user_recover = pickle.loads(user_pkl)           # 重构为新版User对象\n",
    "print(user_recover.email)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### 6.6.3 shelve\n",
    "\n",
    "- shelve模块是对pickle模块的封装，提供了更加便捷的序列化和反序列化功能\n",
    "- shelve模块中的open函数会打开序列化数据文件并返回一个特殊的字典，该字典中包含了保存在文件中的序列化数据\n",
    "  - `writeback`参数用于控制是否可写入新的数据至序列化文件"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "list：\t[1, 2.0, 3, (4+5j)]\n",
      "tuple：\t('字符串数据', b'byte string')\n",
      "set：\t{False, True, None}\n",
      "obj：\t<__main__.Test object at 0x7fa5725ff3a0>\n"
     ]
    }
   ],
   "source": [
    "import shelve\n",
    "\n",
    "class Test:\n",
    "    pass\n",
    "\n",
    "d1 = [1, 2.0, 3, 4+5j]\n",
    "d2 = (\"字符串数据\", b\"byte string\")\n",
    "d3 = {None, True, False}\n",
    "d4 = Test()\n",
    "\n",
    "# 序列化，以可写入方式打开文件\n",
    "with shelve.open('shelve.data') as shelve_file:\n",
    "    shelve_file['list'] = d1\n",
    "    shelve_file['tuple'] = d2\n",
    "    shelve_file['set'] = d3\n",
    "    shelve_file['obj'] = d4\n",
    "\n",
    "# 反序列化，以不可写入方式打开文件\n",
    "with shelve.open('shelve.data', writeback=False) as shelve_file:\n",
    "    for key, value in shelve_file.items():\n",
    "        print(f'{key}：\\t{value}')"
   ]
  }
 ],
 "metadata": {
  "author": "liuchen",
  "celltoolbar": "幻灯片",
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.1"
  },
  "rise": {
   "enable_chalkboard": true,
   "footer": "",
   "progress": true,
   "scroll": true,
   "slideNumber": true
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  },
  "url": "https://github.com/hitlic/python_book"
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
